package com.hyper_yang._05_juc.chap03;

//资源类    wait/notify、notifyAll 必须在有锁的情况下使。Object类提供的方法。
// 虚假唤醒: 使用 if判断，消费者被唤醒后是从 wait()【被阻塞的地方】后面执行，而不是重新从同步块开头
class ShareDataOne extends Object{
    private int number = 0;

    //加
    public synchronized void increment() throws InterruptedException {
        //判断
        //if(number==1){ //由于if判断，导致虚假唤醒。所以，不能使用if判断。
        while (number==1){ // 使用while代替if进行判断，可以避免虚假唤醒。
            this.wait();
        }

        //干活
        number ++ ;
        System.out.println(Thread.currentThread().getName()+" number = " + number);

        //通知
        this.notifyAll();
    }

    //减
    public synchronized void decrement() throws InterruptedException {
        //判断
        while(number==0){
            this.wait();
        }

        //干活
        number -- ;
        System.out.println(Thread.currentThread().getName()+" number = " + number);

        //通知
        this.notifyAll();
    }
}

/**
 * 多线程模板（上）
 *      高内聚、低耦合   线程 操作 资源类
 * 多线程模板（中）
 *      判断   干活   通知
 * 多线程模板(下)
 *      while代替if判断，避免虚假唤醒。
 *
 *  需求：两个线程操作一个初始值为0的变量，实现一个线程对变量增加1，一个线程对变量减少1，交替10轮。
 */
public class WaitNotifyDemo {
    public static void main(String[] args) {
        ShareDataOne shareDataOne = new ShareDataOne();

        new Thread(()->{
            for (int i = 1; i <= 10; i++) {
                try {
                    shareDataOne.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();

        new Thread(()->{
            for (int i = 1; i <= 10; i++) {
                try {
                    shareDataOne.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();


        new Thread(()->{
            for (int i = 1; i <= 10; i++) {
                try {
                    shareDataOne.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();

        new Thread(()->{
            for (int i = 1; i <= 10; i++) {
                try {
                    shareDataOne.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }
}
